using System;
using System.Collections;
using System.Collections.Generic;

// 动作系统（单例模式），负责管理游戏动作的执行流程
public class ActionSystem : SingletonMono<ActionSystem>
{
    private List<GameAction> reactions = null;  // 当前待执行的反应动作列表

    public bool IsPerforming { get; private set; } = false; // 标记系统是否正在执行动作（防止重复执行）

    // 预订阅字典（按动作类型存储预执行回调）
    private static Dictionary<Type, List<Action<GameAction>>> preSubs = new();

    // 后订阅字典（按动作类型存储后执行回调）
    private static Dictionary<Type, List<Action<GameAction>>> postSubs = new();

    // 执行器字典（存储各类型动作的执行协程）
    private static Dictionary<Type, Func<GameAction, IEnumerator>> performers = new();

    // 存储所有原始委托与包装委托的映射关系（解决取消订阅问题）
    private static Dictionary<Delegate, Action<GameAction>> wrappedDelegates = new();

    /// <summary>
    /// 添加反应动作到当前执行流程
    /// </summary>
    public void AddReaction(GameAction gameAction)
    {
        reactions?.Add(gameAction); // 安全添加（reactions为null时不操作）
    }

    /// <summary>
    /// 执行游戏动作的主入口
    /// </summary>
    /// <param name="OnPerformFinished">执行完成后的回调</param>
    public void Perform(GameAction action, Action OnPerformFinished = null)
    {
        if (IsPerforming) return; // 防止动作嵌套执行

        IsPerforming = true;
        StartCoroutine(Flow(action, () =>
        {
            IsPerforming = false;
            OnPerformFinished?.Invoke(); // 安全调用完成回调
        }));
    }

    /// <summary>
    /// 动作执行流程协程（核心三阶段逻辑）
    /// </summary>
    private IEnumerator Flow(GameAction action, Action OnFlowFinished = null)
    {
        // 阶段1：前置处理
        reactions = action.PreReactions;
        PerformSubscribers(action, preSubs); // 触发所有预订阅回调
        yield return PerformReactions();    // 执行前置反应链

        // 阶段2：主执行
        reactions = action.PerformReactions;
        yield return PerformPerformer(action); // 执行主逻辑协程
        yield return PerformReactions();       // 执行同步反应

        // 阶段3：后置处理
        reactions = action.PostReactions;
        PerformSubscribers(action, postSubs); // 触发所有后订阅回调
        yield return PerformReactions();      // 执行后置反应链

        OnFlowFinished?.Invoke(); // 流程结束回调
    }

    // 执行特定类型动作的协程
    private IEnumerator PerformPerformer(GameAction action)
    {
        Type type = action.GetType();
        if (performers.ContainsKey(type))
        {
            yield return performers[type](action);
        }
    }

    // 触发订阅者回调（统一处理pre/post）
    private void PerformSubscribers(GameAction action, Dictionary<Type, List<Action<GameAction>>> subs)
    {
        Type type = action.GetType();
        if (subs.ContainsKey(type))
        {
            foreach (var sub in subs[type])
            {
                sub(action);
            }
        }
    }

    // 递归执行反应链
    private IEnumerator PerformReactions()
    {
        foreach (var reaction in reactions)
        {
            yield return Flow(reaction); // 递归执行子动作
        }
    }

    // 注册动作执行逻辑
    public static void AttachPerformer<T>(Func<T, IEnumerator> performer) where T : GameAction
    {
        Type type = typeof(T);
        // 包装泛型参数为基类参数
        IEnumerator wrappedPerformer(GameAction action) => performer((T)action);
        if (performers.ContainsKey(type))
            performers[type] = wrappedPerformer; // 更新现有执行器
        else
            performers.Add(type, wrappedPerformer); // 添加新执行器
    }

    // 注销动作执行逻辑
    public static void DetachPerformer<T>() where T : GameAction
    {
        Type type = typeof(T);
        if (performers.ContainsKey(type))
            performers.Remove(type);
    }

    /// <summary>
    /// 订阅动作反应（可在动作执行前/后触发）
    /// </summary>
    /// <typeparam name="T">具体动作类型</typeparam>
    /// <param name="reaction">要订阅的回调方法</param>
    /// <param name="timing">订阅时机（PRE前/POST后）</param>
    public static void SubscribeReaction<T>(Action<T> reaction, ReactionTiming timing) where T : GameAction
    {
        // 根据时机选择订阅字典
        var subs = timing == ReactionTiming.PRE ? preSubs : postSubs;

        // 包装泛型回调
        // void wrappedReaction(GameAction action) => reaction((T)action);

        Type type = typeof(T);
        // if (!subs.ContainsKey(type))
        // {
        //     subs.Add(type, new());// 如果不存在，先新建List
        // }
        // subs[type].Add(wrappedReaction);

        // 如果已经存在相同委托的包装，直接返回（避免重复订阅）
        if (wrappedDelegates.ContainsKey(reaction)) return;

        // 创建泛型包装委托：将GameAction转换为具体类型T后调用原始委托
        Action<GameAction> wrappedReaction = action => reaction((T)action);

        // 记录原始委托与包装委托的映射关系
        wrappedDelegates[reaction] = wrappedReaction;

        // 获取或创建该类型对应的回调列表
        if (!subs.TryGetValue(type, out var list))
        {
            list = new();// 如果不存在，先新建List
            subs[type] = list;
        }

        // 将包装后的委托添加到订阅列表
        list.Add(wrappedReaction);
    }

    /// <summary>
    /// 取消订阅动作反应
    /// </summary>
    /// <typeparam name="T">具体动作类型</typeparam>
    /// <param name="reaction">要取消的回调方法</param>
    /// <param name="timing">订阅时机（PRE前/POST后）</param>
    public static void UnsubscribeReaction<T>(Action<T> reaction, ReactionTiming timing) where T : GameAction
    {
        var subs = timing == ReactionTiming.PRE ? preSubs : postSubs;

        Type type = typeof(T);
        // if (subs.ContainsKey(type))
        // {
        //     void wrappedReaction(GameAction action) => reaction((T)action);
        //     subs[type].Remove(wrappedReaction);
        // }

        // 通过原始委托查找对应的包装委托
        if (wrappedDelegates.TryGetValue(reaction, out var wrappedReaction))
        {
            // 从对应类型的订阅列表中移除包装委托
            if (subs.TryGetValue(type, out var list))
            {
                list.Remove(wrappedReaction);
            }

            // 清理映射关系
            wrappedDelegates.Remove(reaction);
        }
    }
}